/*

* ------------------------------------------------------------------------
* ------------------------------------------------------------------------
* |     Smart-Shop开源商城系统/ Java商城-首选电商平台系统 请务必保留此注释头信息
* |     开源地址: https://gitee.com/ningbo-qishan/gruul-mall
* ------------------------------------------------------------------------
* ------------------------------------------------------------------------
* |     可正常分享和学习源码,未经授权 不可商用！
* |     商业版中台购买/开源版商业授权 联系技术客服
* |     官网:  https://www.73app.cn/
* ------------------------------------------------------------------------
* ------------------------------------------------------------------------
* |     Copyright (c) 2016-2999 宁波启山智软科技有限公司
* |     版权所有 ,侵权必究！
* ------------------------------------------------------------------------

*/
package com.medusa.gruul.platform.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.map.MapBuilder;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.medusa.gruul.common.core.constant.CommonConstants;
import com.medusa.gruul.common.core.exception.ServiceException;
import com.medusa.gruul.common.core.util.PageUtils;
import com.medusa.gruul.common.core.util.StringUtil;
import com.medusa.gruul.platform.api.entity.AgentInfo;
import com.medusa.gruul.platform.api.entity.AgentWithdrawOrder;
import com.medusa.gruul.platform.conf.MeConstant;
import com.medusa.gruul.platform.constant.AgentNoticeEnum;
import com.medusa.gruul.platform.mapper.AgentWithdrawOrderMapper;
import com.medusa.gruul.platform.model.dto.agent.ApplyWithdrawDto;
import com.medusa.gruul.platform.model.dto.agent.WithdrawOrderAuditDto;
import com.medusa.gruul.platform.model.vo.agent.AdminWithdrawOrdersVo;
import com.medusa.gruul.platform.model.vo.agent.WithdrawOrdersVo;
import com.medusa.gruul.platform.service.IAgentInfoService;
import com.medusa.gruul.platform.service.IAgentNoticeService;
import com.medusa.gruul.platform.service.IAgentWithdrawOrderService;
import com.medusa.gruul.platform.stp.StpAgentUtil;
import org.apache.groovy.util.Maps;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 提现工单表结构 服务实现类
 * </p>
 *
 * @author whh
 * @since 2020-10-04
 */
@Service
public class AgentWithdrawOrderServiceImpl extends ServiceImpl<AgentWithdrawOrderMapper, AgentWithdrawOrder> implements IAgentWithdrawOrderService {

    @Autowired
    private IAgentInfoService agentInfoService;

    @Autowired
    private IAgentNoticeService agentNoticeService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void applyWithdraw(ApplyWithdrawDto withdrawDto) {
        AgentInfo agentInfo = agentInfoService.getById(StpAgentUtil.getLoginIdAsLong());
        BigDecimal sub = NumberUtil.sub(agentInfo.getAvailableAmount(),withdrawDto.getAmount());
        if (sub.compareTo(new BigDecimal(MeConstant.ZERO)) < 0) {
            throw new ServiceException("可用余额不足,无法申请提现");
        }
        if (withdrawDto.getType().equals(CommonConstants.NUMBER_THREE) && StrUtil.isEmpty(withdrawDto.getBankName())) {
            throw new ServiceException("开户行不能为空");
        }
        AgentWithdrawOrder withdrawOrder = BeanUtil.toBean(withdrawDto, AgentWithdrawOrder.class);
        withdrawOrder.setStatus(CommonConstants.NUMBER_ZERO);
        withdrawOrder.setOrderNum(IdUtil.getSnowflake(1, 1).nextIdStr());
        withdrawOrder.setAgentType(agentInfo.getType());
        withdrawOrder.setAccount(agentInfo.getAccount());
        withdrawOrder.setLinkName(agentInfo.getLinkName());
        withdrawOrder.setAgentInfoId(agentInfo.getId());
        this.save(withdrawOrder);
        //处理用户可用余额减少，增加冻结金额
        AgentInfo up = new AgentInfo();
        up.setId(agentInfo.getId());
        up.setAvailableAmount(sub);
        up.setFreezeAmount(NumberUtil.add(agentInfo.getFreezeAmount(), withdrawDto.getAmount()));
        agentInfoService.updateById(up);

        notice(withdrawOrder, CommonConstants.NUMBER_ONE);
    }

    /**
     * @param withdrawOrder com.medusa.gruul.platform.api.entity.AgentWithdrawOrder
     * @param optionType    通知类型  1-提现申请通知  2-提现成功通知  3-提现失败通知
     */
    private void notice(AgentWithdrawOrder withdrawOrder, Integer optionType) {
        String key2 = "";
        switch (withdrawOrder.getType()) {
            case 1:
                key2 = String.format(key2.concat("微信 (%s)"), withdrawOrder
                        .getBankNum()
                        .replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2"));
                break;
            case 2:
                key2 = String.format(key2.concat("支付宝(%s)"), withdrawOrder
                        .getBankNum()
                        .replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2"));
                break;
            case 3:
                key2 = String.format(key2.concat("银行卡号(%s)"), withdrawOrder
                        .getBankNum()
                        .replaceAll("(\\d{4})\\d+(\\d{4})$", "**** **** **** $2"));
                break;
            default:
                break;
        }
        //提现通知
        MapBuilder<String, String> content = MapUtil.<String, String>builder()
                .put("key1", withdrawOrder.getAmount().toString())
                .put("key2", key2)
                .put("key3", LocalDateTimeUtil.format(withdrawOrder.getCreateTime(), "yyyy-MM-dd HH:mm:ss"));
        if (!optionType.equals(CommonConstants.NUMBER_ONE)) {
            content.put("key4", LocalDateTimeUtil.format(LocalDateTimeUtil.now(), "yyyy-MM-dd HH:mm:ss"));
        }
        AgentNoticeEnum noticeEnum = null;
        // 通知类型  1-提现申请通知  2-提现成功通知  3-提现失败通知
        switch (optionType) {
            case 1:
                noticeEnum = AgentNoticeEnum.MSG_0021;
                break;
            case 2:
                noticeEnum = AgentNoticeEnum.MSG_0023;
                break;
            case 3:
                noticeEnum = AgentNoticeEnum.MSG_0022;
                break;
            default:
                throw new ServiceException("数据异常");
        }
        agentNoticeService.newNotice(withdrawOrder.getAgentInfoId(), noticeEnum, null, content.build(),CommonConstants.NUMBER_TWO);
    }

    @Override
    public PageUtils<WithdrawOrdersVo> withdrawOrders(Integer page, Integer size, Integer status, Integer type, String startTime, String endTime, String orderNumber) {
        Page<AgentWithdrawOrder> iPage = this.baseMapper.selectPage(new Page<AgentWithdrawOrder>(page, size), new QueryWrapper<AgentWithdrawOrder>()
                .eq("status", status)
                .ge(StringUtil.isNotEmpty(startTime), "create_time", startTime)
                .le(StringUtil.isNotEmpty(endTime), "create_time", endTime)
                .eq("agent_info_id", StpAgentUtil.getLoginId())
                .eq(StringUtil.isNotEmpty(orderNumber), "order_num", orderNumber)
                .eq(ObjectUtil.isNotNull(type), "type", type)
        );
        List<AgentWithdrawOrder> records = iPage.getRecords();
        if (records.size() == 0) {
            return new PageUtils(null, (int) iPage.getTotal(), (int) iPage.getSize(), (int) iPage.getCurrent());
        }
        List<WithdrawOrdersVo> listVos = records.stream().map(obj -> {
            WithdrawOrdersVo vo = new WithdrawOrdersVo();
            BeanUtils.copyProperties(obj, vo, "linkName", "account", "agentType");
            return vo;
        }).collect(Collectors.toList());

        return new PageUtils(listVos, (int) iPage.getTotal(), (int) iPage.getSize(), (int) iPage.getCurrent());
    }

    @Override
    public AdminWithdrawOrdersVo adminWithdrawOrders(Integer page, Integer size, Integer status, Integer type, String startTime, String endTime, String search, Integer agentType) {
        AdminWithdrawOrdersVo result = new AdminWithdrawOrdersVo();
        result.setTotleAmount(new BigDecimal("0.0"));
        QueryWrapper<AgentWithdrawOrder> queryWrapper = new QueryWrapper<AgentWithdrawOrder>()
                .eq("status", status)
                .ge(StringUtil.isNotEmpty(startTime), "create_time", startTime)
                .le(StringUtil.isNotEmpty(endTime), "create_time", endTime)
                .eq(ObjectUtil.isNotNull(type), "type", type)
                .eq(ObjectUtil.isNotNull(agentType), "agent_type", agentType);
        Page<AgentWithdrawOrder> iPage = this.baseMapper.selectPage(new Page<>(page, size), queryWrapper);
        List<AgentWithdrawOrder> records = iPage.getRecords();
        if (records.size() == 0) {
            result.setVos(new PageUtils(null, (int) iPage.getTotal(), (int) iPage.getSize(), (int) iPage.getCurrent()));

            return result;
        }
        List<WithdrawOrdersVo> listVos = records.stream().map(obj -> {
            WithdrawOrdersVo vo = new WithdrawOrdersVo();
            BeanUtils.copyProperties(obj, vo);
            return vo;
        }).collect(Collectors.toList());
        result.setVos(new PageUtils(listVos, (int) iPage.getTotal(), (int) iPage.getSize(), (int) iPage.getCurrent()));
        queryWrapper.select("sum(amount)");
        List<Object> totle = this.baseMapper.selectObjs(queryWrapper);
        if (CollectionUtil.isNotEmpty(totle)) {
            result.setTotleAmount((BigDecimal) totle.get(0));
        }
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void withdrawOrderAudit(WithdrawOrderAuditDto dto) {
        AgentWithdrawOrder withdrawOrder = this.getById(dto.getId());
        if (withdrawOrder == null) {
            throw new ServiceException("工单错误");
        }
        if (!withdrawOrder.getStatus().equals(CommonConstants.NUMBER_ZERO)) {
            throw new ServiceException("工单已处理");
        }
        AgentInfo agentInfo = agentInfoService.getById(withdrawOrder.getAgentInfoId());
        if (agentInfo == null) {
            throw new ServiceException("数据异常");
        }
        AgentInfo up = new AgentInfo();
        up.setId(agentInfo.getId());
        Integer optionType = CommonConstants.NUMBER_THREE;
        //拒绝
        if (dto.getOptionType().equals(CommonConstants.NUMBER_ONE)) {
            //冻结金额减少,有效金额增加
            up.setFreezeAmount(NumberUtil.sub(agentInfo.getFreezeAmount(), withdrawOrder.getAmount()));
            up.setAvailableAmount(NumberUtil.add(agentInfo.getAvailableAmount(), withdrawOrder.getAmount()));
        }
        //同意
        if (dto.getOptionType().equals(CommonConstants.NUMBER_TWO)) {
            //冻结金额直接解冻
            up.setFreezeAmount(NumberUtil.sub(agentInfo.getFreezeAmount(), withdrawOrder.getAmount()));
            optionType = CommonConstants.NUMBER_TWO;
        }
        up.updateById();
        withdrawOrder.setStatus(dto.getOptionType());
        this.updateById(withdrawOrder);
        notice(withdrawOrder, optionType);

    }
}
